package moore.generator

import java.io.ByteArrayInputStream
import java.util.ArrayList
import java.util.List
import moore.ASM
import moore.Input
import moore.MoorePackage
import moore.OutputList
import moore.generator.template.MsfArchitettureTemplate
import moore.generator.template.MsfEntityTemplate
import moore.generator.template.MsfFTemplate
import moore.generator.template.MsfGtemplate
import moore.generator.template.PipoTemplateClass
import moore.valueState
import org.eclipse.core.resources.IFile
import org.eclipse.core.resources.IFolder
import org.eclipse.core.runtime.NullProgressMonitor
import org.eclipse.emf.ecore.resource.Resource
import org.eclipse.emf.ecore.util.EcoreUtil

class vhdlGenerator {
	private static vhdlGenerator generatorInstace=null;
	private Resource model;
	private ArrayList<String> fInput=new ArrayList<String>();
	private ArrayList<String> gOutput=new ArrayList<String>();
	private String asmName=null;
	private ASM asmModel=null;
	int stateDim
	List<valueState> states;
	
	def private vhdlGenerator(){
	}
	
	def public static vhdlGenerator getInstance(){
		if(generatorInstace==null){
			generatorInstace=new vhdlGenerator();
		}else{
			generatorInstace.resetInstance();
		}
		return generatorInstace;
	}
	
	def public void generate(Resource resource,IFolder srcGenFolder){
		var String msfModuleContent="";
		if(resource==null){
			throw new NullPointerException("risorsa non trovata");
		}
		this.model=resource;
		//genero la entity principale del MSF
		msfModuleContent+=this.generateMsfEntity();
		//genero l'architecture dell'MSF
		msfModuleContent+=this.generateMsfArchitecture(); 
		this.createFile(srcGenFolder,this.asmName+".vhd",msfModuleContent)
		//genero la f
		var String msfFContent="";
		msfFContent=this.generetaMsfF();
		this.createFile(srcGenFolder,this.asmName+"_F.vhd",msfFContent);
		//genero la g
		var String msfGContent="";
		msfGContent=this.generateMsfG();
		this.createFile(srcGenFolder,this.asmName+"_G.vhd",msfGContent);
		//genero la libreria per il pipo
		var String pipoContent="";
		pipoContent=PipoTemplateClass.getPipo();
		this.createFile(srcGenFolder,"PIPO.vhd",pipoContent);
	}
	
	def private String generateMsfEntity(){
		//recupero il nome dell'ASM e quindi dell'MSF
		asmModel=this.model.contents.get(0) as ASM;
		this.asmName=asmModel.name;
		//recupero la lista di tutti gli input
		var inputs=EcoreUtil.getObjectsByType(asmModel.composedOf,MoorePackage.eINSTANCE.input);
		for(input:inputs){
			if(!this.fInput.contains((input as Input).name))
				this.fInput.add((input as Input).name);
		}
		//recupero la lista di tutti gli output
		var outputs=EcoreUtil.getObjectsByType(asmModel.composedOf,MoorePackage.eINSTANCE.outputList);
		var outputlist=(outputs.get(0) as OutputList).y;
		for(output:outputlist){
			this.gOutput.add(output);
		}
		MsfEntityTemplate.getEntityMsfPart(asmName,this.fInput,this.gOutput);
	}
		
	def private String generateMsfArchitecture(){
		//recupero il numero di stati dell'asm
		states=EcoreUtil.getObjectsByType(this.asmModel.composedOf,MoorePackage.eINSTANCE.getvalueState).toList;
		var Double dsize=Double.valueOf((Math.log(Float.valueOf(states.size))/Math.log(2)));
		stateDim=Math.ceil(dsize).intValue;
		return MsfArchitettureTemplate.getArchitectureMsfPart(this.asmName,stateDim,this.fInput,this.gOutput);
	}
	  
	def private String generetaMsfF(){
		MsfFTemplate.getMsfF(this.asmName,this.fInput,this.stateDim,this.states);
	}
	
	def private String generateMsfG(){
		return MsfGtemplate.getMsfG(this.asmName,this.gOutput,this.stateDim,this.states);
	}
	
	def private createFile(IFolder srcGenFolder,String FileNAme,String content){
		var IFile file=srcGenFolder.getFile(FileNAme);
		if(file.exists)
			file.delete(true,new NullProgressMonitor);
		var byte[] b=content.getBytes("UTF-8");	
		file.create(new ByteArrayInputStream(b),true,new NullProgressMonitor);	
	}
	
	def private resetInstance(){
		this.fInput=new ArrayList<String>();
		this.gOutput=new ArrayList<String>();
	}
}